/******************************************************************************* * Copyright (c) 2000, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Francis Upton - <francisu@ieee.org> - Bug 217777 * Tristan Hume - <trishume@gmail.com> - Bug 2369 * Lars Vogel <Lars.Vogel@vogella.com> - Bug 422533, 440136, 445724, 366708, 418661, 456897, 472654, 481516, 486543 * Terry Parker <tparker@google.com> - Bug 416673 * Sergey Prigogin <eclipse.sprigogin@gmail.com> - Bug 438324 * Snjezana Peco <snjeza.peco@gmail.com> - Bug 405542 * Andrey Loskutov <loskutov@gmx.de> - Bug 372799 * Mickael Istria (Red Hat Inc.) - Bug 469918 * Patrik Suzzi <psuzzi@gmail.com> - Bug 487297 *******************************************************************************/ package org.eclipse.ui.internal; import com.ibm.icu.util.ULocale; import com.ibm.icu.util.ULocale.Category; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import org.eclipse.core.commands.Command; import org.eclipse.core.commands.CommandManager; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.NotEnabledException; import org.eclipse.core.commands.NotHandledException; import org.eclipse.core.commands.common.EventManager; import org.eclipse.core.commands.common.NotDefinedException; import org.eclipse.core.commands.contexts.ContextManager; import org.eclipse.core.databinding.observable.Realm; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionDelta; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IPlatformRunnable; import org.eclipse.core.runtime.IProduct; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IRegistryChangeListener; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.e4.core.contexts.ContextFunction; import org.eclipse.e4.core.contexts.ContextInjectionFactory; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.core.di.InjectionException; import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.e4.ui.internal.workbench.E4Workbench; import org.eclipse.e4.ui.internal.workbench.renderers.swt.IUpdateService; import org.eclipse.e4.ui.internal.workbench.swt.E4Application; import org.eclipse.e4.ui.internal.workbench.swt.IEventLoopAdvisor; import org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine; import org.eclipse.e4.ui.model.application.MApplication; import org.eclipse.e4.ui.model.application.commands.MBindingContext; import org.eclipse.e4.ui.model.application.commands.MBindingTable; import org.eclipse.e4.ui.model.application.commands.MCategory; import org.eclipse.e4.ui.model.application.commands.MCommand; import org.eclipse.e4.ui.model.application.commands.MCommandsFactory; import org.eclipse.e4.ui.model.application.commands.impl.CommandsFactoryImpl; import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor; import org.eclipse.e4.ui.model.application.ui.MElementContainer; import org.eclipse.e4.ui.model.application.ui.basic.MPart; import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar; import org.eclipse.e4.ui.model.application.ui.basic.MTrimElement; import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow; import org.eclipse.e4.ui.model.application.ui.basic.MWindow; import org.eclipse.e4.ui.model.application.ui.basic.impl.BasicFactoryImpl; import org.eclipse.e4.ui.model.application.ui.menu.MMenu; import org.eclipse.e4.ui.model.application.ui.menu.MToolBar; import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution; import org.eclipse.e4.ui.services.EContextService; import org.eclipse.e4.ui.workbench.IModelResourceHandler; import org.eclipse.e4.ui.workbench.IPresentationEngine; import org.eclipse.e4.ui.workbench.UIEvents; import org.eclipse.e4.ui.workbench.modeling.EModelService; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.ExternalActionManager; import org.eclipse.jface.action.ExternalActionManager.CommandCallback; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.bindings.BindingManager; import org.eclipse.jface.bindings.IBindingManagerListener; import org.eclipse.jface.databinding.swt.DisplayRealm; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.operation.ModalContext; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.preference.PreferenceManager; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.BidiUtils; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.OpenStrategy; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.window.IShellProvider; import org.eclipse.jface.window.Window; import org.eclipse.osgi.service.runnable.StartupMonitor; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.graphics.DeviceData; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IDecoratorManager; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorRegistry; import org.eclipse.ui.IElementFactory; import org.eclipse.ui.ILocalWorkingSetManager; import org.eclipse.ui.IMemento; import org.eclipse.ui.IPerspectiveDescriptor; import org.eclipse.ui.IPerspectiveRegistry; import org.eclipse.ui.ISaveableFilter; import org.eclipse.ui.ISaveablesLifecycleListener; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.ISourceProvider; import org.eclipse.ui.ISources; import org.eclipse.ui.IViewReference; import org.eclipse.ui.IWindowListener; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchCommandConstants; import org.eclipse.ui.IWorkbenchListener; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPreferenceConstants; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkingSetManager; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.Saveable; import org.eclipse.ui.WorkbenchException; import org.eclipse.ui.XMLMemento; import org.eclipse.ui.activities.IWorkbenchActivitySupport; import org.eclipse.ui.application.WorkbenchAdvisor; import org.eclipse.ui.browser.IWorkbenchBrowserSupport; import org.eclipse.ui.commands.ICommandImageService; import org.eclipse.ui.commands.ICommandService; import org.eclipse.ui.commands.IWorkbenchCommandSupport; import org.eclipse.ui.contexts.IContextService; import org.eclipse.ui.contexts.IWorkbenchContextSupport; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.help.IWorkbenchHelpSystem; import org.eclipse.ui.internal.StartupThreading.StartupRunnable; import org.eclipse.ui.internal.actions.CommandAction; import org.eclipse.ui.internal.activities.ws.WorkbenchActivitySupport; import org.eclipse.ui.internal.browser.WorkbenchBrowserSupport; import org.eclipse.ui.internal.commands.CommandImageManager; import org.eclipse.ui.internal.commands.CommandImageService; import org.eclipse.ui.internal.commands.CommandService; import org.eclipse.ui.internal.commands.WorkbenchCommandSupport; import org.eclipse.ui.internal.contexts.ActiveContextSourceProvider; import org.eclipse.ui.internal.contexts.ContextService; import org.eclipse.ui.internal.contexts.WorkbenchContextSupport; import org.eclipse.ui.internal.dialogs.PropertyPageContributorManager; import org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor; import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart; import org.eclipse.ui.internal.e4.compatibility.E4Util; import org.eclipse.ui.internal.e4.migration.WorkbenchMigrationProcessor; import org.eclipse.ui.internal.handlers.LegacyHandlerService; import org.eclipse.ui.internal.help.WorkbenchHelpSystem; import org.eclipse.ui.internal.intro.IIntroRegistry; import org.eclipse.ui.internal.intro.IntroDescriptor; import org.eclipse.ui.internal.keys.BindingService; import org.eclipse.ui.internal.menus.FocusControlSourceProvider; import org.eclipse.ui.internal.menus.WorkbenchMenuService; import org.eclipse.ui.internal.misc.Policy; import org.eclipse.ui.internal.misc.StatusUtil; import org.eclipse.ui.internal.misc.UIStats; import org.eclipse.ui.internal.model.ContributionService; import org.eclipse.ui.internal.progress.ProgressManager; import org.eclipse.ui.internal.progress.ProgressManagerUtil; import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants; import org.eclipse.ui.internal.registry.UIExtensionTracker; import org.eclipse.ui.internal.registry.ViewDescriptor; import org.eclipse.ui.internal.services.EvaluationService; import org.eclipse.ui.internal.services.IServiceLocatorCreator; import org.eclipse.ui.internal.services.IWorkbenchLocationService; import org.eclipse.ui.internal.services.MenuSourceProvider; import org.eclipse.ui.internal.services.ServiceLocator; import org.eclipse.ui.internal.services.ServiceLocatorCreator; import org.eclipse.ui.internal.services.SourceProviderService; import org.eclipse.ui.internal.services.WorkbenchLocationService; import org.eclipse.ui.internal.splash.EclipseSplashHandler; import org.eclipse.ui.internal.splash.SplashHandlerFactory; import org.eclipse.ui.internal.testing.ContributionInfoMessages; import org.eclipse.ui.internal.testing.WorkbenchTestable; import org.eclipse.ui.internal.themes.ColorDefinition; import org.eclipse.ui.internal.themes.FontDefinition; import org.eclipse.ui.internal.themes.ThemeElementHelper; import org.eclipse.ui.internal.themes.WorkbenchThemeManager; import org.eclipse.ui.internal.tweaklets.GrabFocus; import org.eclipse.ui.internal.tweaklets.Tweaklets; import org.eclipse.ui.internal.util.PrefUtil; import org.eclipse.ui.intro.IIntroManager; import org.eclipse.ui.keys.IBindingService; import org.eclipse.ui.menus.IMenuService; import org.eclipse.ui.model.IContributionService; import org.eclipse.ui.operations.IWorkbenchOperationSupport; import org.eclipse.ui.progress.IProgressService; import org.eclipse.ui.progress.WorkbenchJob; import org.eclipse.ui.services.IDisposable; import org.eclipse.ui.services.IEvaluationService; import org.eclipse.ui.services.IServiceScopes; import org.eclipse.ui.services.ISourceProviderService; import org.eclipse.ui.splash.AbstractSplashHandler; import org.eclipse.ui.statushandlers.StatusManager; import org.eclipse.ui.swt.IFocusService; import org.eclipse.ui.testing.ContributionInfo; import org.eclipse.ui.themes.ITheme; import org.eclipse.ui.themes.IThemeManager; import org.eclipse.ui.views.IViewDescriptor; import org.eclipse.ui.views.IViewRegistry; import org.eclipse.ui.wizards.IWizardRegistry; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.Constants; import org.osgi.framework.ServiceRegistration; import org.osgi.framework.SynchronousBundleListener; import org.osgi.util.tracker.ServiceTracker; /** * The workbench class represents the top of the Eclipse user interface. Its * primary responsibility is the management of workbench windows, dialogs, * wizards, and other workbench-related windows. * <p> * Note that any code that is run during the creation of a workbench instance * should not required access to the display. * </p> */ public final class Workbench extends EventManager implements IWorkbench, org.eclipse.e4.ui.workbench.IWorkbench { public static String WORKBENCH_AUTO_SAVE_JOB = "Workbench Auto-Save Job"; //$NON-NLS-1$ private static final String WORKBENCH_AUTO_SAVE_BACKGROUND_JOB = "Workbench Auto-Save Background Job"; //$NON-NLS-1$ public static String MEMENTO_KEY = "memento"; //$NON-NLS-1$ public static final String EDITOR_TAG = "Editor"; //$NON-NLS-1$ private static final String PROP_VM = "eclipse.vm"; //$NON-NLS-1$ private static final String PROP_VMARGS = "eclipse.vmargs"; //$NON-NLS-1$ private static final String PROP_COMMANDS = "eclipse.commands"; //$NON-NLS-1$ private static final String PROP_EXIT_CODE = "eclipse.exitcode"; //$NON-NLS-1$ private static final String CMD_DATA = "-data"; //$NON-NLS-1$ private static final String CMD_VMARGS = "-vmargs"; //$NON-NLS-1$ private final class StartupProgressBundleListener implements SynchronousBundleListener { private final IProgressMonitor progressMonitor; private final int maximumProgressCount; // stack of names of bundles currently starting private final List<String> starting; StartupProgressBundleListener(IProgressMonitor progressMonitor, int maximumProgressCount) { super(); this.progressMonitor = progressMonitor; this.maximumProgressCount = maximumProgressCount; this.starting = new ArrayList<>(); } @Override public void bundleChanged(BundleEvent event) { int eventType = event.getType(); String bundleName; boolean worked = false; // Note: no calls to any non-trivial Eclipse code outside this class // should be made inside the synchronized block below. Such calls // can cause deadlocks on startup, see bug 502095. // Progress monitor calls *are* non-trivial. synchronized (this) { if (eventType == BundleEvent.STARTING) { starting.add(bundleName = event.getBundle().getSymbolicName()); } else if (eventType == BundleEvent.STARTED) { progressCount++; if (progressCount <= maximumProgressCount) { worked = true; } int index = starting.lastIndexOf(event.getBundle().getSymbolicName()); if (index >= 0) { starting.remove(index); } if (index != starting.size()) { return; // not currently displayed } bundleName = index == 0 ? null : (String) starting.get(index - 1); } else { return; // uninteresting event } } if (worked) { progressMonitor.worked(1); } if (bundleName != null) { String taskName = NLS.bind(WorkbenchMessages.Startup_Loading, bundleName); progressMonitor.subTask(taskName); } } } /** * Family for the early startup job. */ public static final String EARLY_STARTUP_FAMILY = "earlyStartup"; //$NON-NLS-1$ public static final String DEFAULT_WORKBENCH_STATE_FILENAME = "workbench.xml"; //$NON-NLS-1$ /** * Holds onto the only instance of Workbench. */ private static Workbench instance; /** * The testable object facade. * * @since 3.0 */ private static WorkbenchTestable testableObject; /** * Signals that the workbench should create a splash implementation when * instantiated. Initial value is <code>true</code>. * * @since 3.3 */ private static boolean createSplash = true; /** * The splash handler. */ private static AbstractSplashHandler splash; /** * The display used for all UI interactions with this workbench. * * @since 3.0 */ private Display display; private boolean workbenchAutoSave = true; private EditorHistory editorHistory; private boolean runEventLoop = true; private boolean isStarting = true; private boolean isClosing = false; /** * A boolean field to indicate whether all the workbench windows have been * closed or not. */ private boolean windowsClosed = false; /** * PlatformUI return code (as opposed to IPlatformRunnable return code). */ private int returnCode = PlatformUI.RETURN_UNSTARTABLE; /** * Advisor providing application-specific configuration and customization of * the workbench. * * @since 3.0 */ private WorkbenchAdvisor advisor; /** * Object for configuring the workbench. Lazily initialized to an instance * unique to the workbench instance. * * @since 3.0 */ private WorkbenchConfigurer workbenchConfigurer; // for dynamic UI /** * ExtensionEventHandler handles extension life-cycle events. */ private ExtensionEventHandler extensionEventHandler; /** * A count of how many large updates are going on. This tracks nesting of * requests to disable services during a large update -- similar to the * <code>setRedraw</code> functionality on <code>Control</code>. When this * value becomes greater than zero, services are disabled. When this value * becomes zero, services are enabled. Please see * <code>largeUpdateStart()</code> and <code>largeUpdateEnd()</code>. */ private int largeUpdates = 0; /** * The service locator maintained by the workbench. These services are * initialized during workbench during the <code>init</code> method. */ private final ServiceLocator serviceLocator; /** * A count of how many plug-ins were loaded while restoring the workbench * state. Initially -1 for unknown number. */ private int progressCount = -1; /** * Listener list for registered IWorkbenchListeners . */ private ListenerList<IWorkbenchListener> workbenchListeners = new ListenerList<>(ListenerList.IDENTITY); private ServiceRegistration workbenchService; private MApplication application; private IEclipseContext e4Context; private IEventBroker eventBroker; private IExtensionRegistry registry; boolean initializationDone = false; private WorkbenchWindow windowBeingCreated = null; private Listener backForwardListener; private Job autoSaveJob; private String id; private ServiceRegistration<?> e4WorkbenchService; // flag used to identify if the application model needs to be saved private boolean applicationModelChanged = false; /** * Creates a new workbench. * * @param display * the display to be used for all UI interactions with the * workbench * @param advisor * the application-specific advisor that configures and * specializes this workbench instance * @since 3.0 */ private Workbench(Display display, final WorkbenchAdvisor advisor, MApplication app, IEclipseContext appContext) { super(); this.id = createId(); StartupThreading.setWorkbench(this); if (instance != null && instance.isRunning()) { throw new IllegalStateException(WorkbenchMessages.Workbench_CreatingWorkbenchTwice); } Assert.isNotNull(display); Assert.isNotNull(advisor); this.advisor = advisor; this.display = display; application = app; e4Context = appContext; Workbench.instance = this; eventBroker = e4Context.get(IEventBroker.class); registry = e4Context.get(IExtensionRegistry.class); appContext.set(getClass().getName(), this); appContext.set(IWorkbench.class, this); appContext.set(IEventLoopAdvisor.class, new IEventLoopAdvisor() { @Override public void eventLoopIdle(Display display) { advisor.eventLoopIdle(display); } @Override public void eventLoopException(Throwable exception) { advisor.eventLoopException(exception); } }); // for dynamic UI [This seems to be for everything that isn't handled by // some // subclass of RegistryManager. I think that when an extension is moved // to the // RegistryManager implementation, then it should be removed from the // list in // ExtensionEventHandler#appear. // I've found that the new wizard extension in particular is a poor // choice to // use as an example, since the result of reading the registry is not // cached // -- so it is re-read each time. The only real contribution of this // dialog is // to show the user a nice dialog describing the addition.] extensionEventHandler = new ExtensionEventHandler(this); registry.addRegistryChangeListener(extensionEventHandler); IServiceLocatorCreator slc = new ServiceLocatorCreator(); serviceLocator = (ServiceLocator) slc.createServiceLocator(null, null, () -> { final Display display1 = getDisplay(); if (display1 != null && !display1.isDisposed()) { MessageDialog.openInformation(null, WorkbenchMessages.Workbench_NeedsClose_Title, WorkbenchMessages.Workbench_NeedsClose_Message); close(PlatformUI.RETURN_RESTART, true); } }, appContext); serviceLocator.registerService(IServiceLocatorCreator.class, slc); serviceLocator.registerService(IWorkbenchLocationService.class, new WorkbenchLocationService(IServiceScopes.WORKBENCH_SCOPE, this, null, null, null, null, 0)); } /** * Returns the one and only instance of the workbench, if there is one. * * @return the workbench, or <code>null</code> if the workbench has not been * created, or has been created and already completed */ public static final Workbench getInstance() { return instance; } private static boolean isFirstE4WorkbenchRun(MApplication app) { return app.getContext().containsKey(E4Workbench.NO_SAVED_MODEL_FOUND); } /** * Creates the workbench and associates it with the the given display and * workbench advisor, and runs the workbench UI. This entails processing and * dispatching events until the workbench is closed or restarted. * <p> * This method is intended to be called by <code>PlatformUI</code>. Fails if * the workbench UI has already been created. * </p> * <p> * The display passed in must be the default display. * </p> * * @param display * the display to be used for all UI interactions with the * workbench * @param advisor * the application-specific advisor that configures and * specializes the workbench * @return return code {@link PlatformUI#RETURN_OK RETURN_OK}for normal * exit; {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the * workbench was terminated with a call to * {@link IWorkbench#restart IWorkbench.restart}; other values * reserved for future use */ public static final int createAndRunWorkbench(final Display display, final WorkbenchAdvisor advisor) { final int[] returnCode = new int[1]; Realm.runWithDefault(DisplayRealm.getRealm(display), () -> { final String nlExtensions = Platform.getNLExtensions(); if (nlExtensions.length() > 0) { ULocale.setDefault(Category.FORMAT, new ULocale(ULocale.getDefault(Category.FORMAT).getBaseName() + nlExtensions)); } System.setProperty(org.eclipse.e4.ui.workbench.IWorkbench.XMI_URI_ARG, "org.eclipse.ui.workbench/LegacyIDE.e4xmi"); //$NON-NLS-1$ Object obj = getApplication(Platform.getCommandLineArgs()); IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); if (!store.isDefault(IPreferenceConstants.LAYOUT_DIRECTION)) { int orientation = store.getInt(IPreferenceConstants.LAYOUT_DIRECTION); Window.setDefaultOrientation(orientation); } if (obj instanceof E4Application) { E4Application e4app = (E4Application) obj; E4Workbench e4Workbench = e4app.createE4Workbench(getApplicationContext(), display); MApplication appModel = e4Workbench.getApplication(); IEclipseContext context = e4Workbench.getContext(); WorkbenchMigrationProcessor migrationProcessor = null; try { migrationProcessor = ContextInjectionFactory.make(WorkbenchMigrationProcessor.class, context); } catch (@SuppressWarnings("restriction") InjectionException e1) { WorkbenchPlugin.log(e1); } if (migrationProcessor != null && isFirstE4WorkbenchRun(appModel) && migrationProcessor.isLegacyWorkbenchDetected()) { try { WorkbenchPlugin .log(StatusUtil.newStatus(IStatus.INFO, "Workbench migration started", null)); //$NON-NLS-1$ migrationProcessor.migrate(); } catch (Exception e2) { WorkbenchPlugin.log("Workbench migration failed", e2); //$NON-NLS-1$ migrationProcessor.restoreDefaultModel(); } } // create the workbench instance Workbench workbench = new Workbench(display, advisor, e4Workbench .getApplication(), e4Workbench.getContext()); // prime the splash nice and early if (createSplash) workbench.createSplashWrapper(); AbstractSplashHandler handler = getSplash(); boolean showProgress = PrefUtil.getAPIPreferenceStore().getBoolean( IWorkbenchPreferenceConstants.SHOW_PROGRESS_ON_STARTUP); IProgressMonitor progressMonitor = null; SynchronousBundleListener bundleListener = null; if (handler != null && showProgress) { progressMonitor = handler.getBundleProgressMonitor(); if (progressMonitor != null) { double cutoff = 0.95; int expectedProgressCount = Math.max(1, WorkbenchPlugin.getDefault() .getBundleCount() / 10); progressMonitor.beginTask("", expectedProgressCount); //$NON-NLS-1$ bundleListener = workbench.new StartupProgressBundleListener( progressMonitor, (int) (expectedProgressCount * cutoff)); WorkbenchPlugin.getDefault().addBundleListener(bundleListener); } } setSearchContribution(appModel, true); // run the legacy workbench once returnCode[0] = workbench.runUI(); if (migrationProcessor != null && migrationProcessor.isWorkbenchMigrated()) { migrationProcessor.updatePartsAfterMigration( WorkbenchPlugin.getDefault().getPerspectiveRegistry(), WorkbenchPlugin.getDefault().getViewRegistry()); WorkbenchPlugin.log(StatusUtil.newStatus(IStatus.INFO, "Workbench migration finished", null)); //$NON-NLS-1$ } if (returnCode[0] == PlatformUI.RETURN_OK) { // run the e4 event loop and instantiate ... well, stuff if (bundleListener != null) { WorkbenchPlugin.getDefault().removeBundleListener(bundleListener); } e4Workbench.createAndRunUI(e4Workbench.getApplication()); IMenuService wms = e4Workbench.getContext().get(IMenuService.class); wms.dispose(); } if (returnCode[0] != PlatformUI.RETURN_UNSTARTABLE) { setSearchContribution(appModel, false); e4app.saveModel(); } // if a restart was triggered via E4Workbench the return // code needs to be set appropriately if (e4Workbench.isRestart()) { returnCode[0] = PlatformUI.RETURN_RESTART; } else { e4Workbench.close(); returnCode[0] = workbench.returnCode; } } }); return returnCode[0]; } private static void setSearchContribution(MApplication app, boolean enabled) { for (MTrimContribution contribution : app.getTrimContributions()) { if ("org.eclipse.ui.ide.application.trimcontribution.QuickAccess".contains(contribution //$NON-NLS-1$ .getElementId())) { // allows us to handle the case where someone opens a workspace // with Luna and then with Kepler contribution.setToBeRendered(enabled); } } } private static ServiceTracker instanceAppContext; static IApplicationContext getApplicationContext() { if (instanceAppContext == null) { instanceAppContext = new ServiceTracker( WorkbenchPlugin.getDefault().getBundleContext(), IApplicationContext.class .getName(), null); instanceAppContext.open(); } return (IApplicationContext) instanceAppContext.getService(); } static Object getApplication(String[] args) { // Find the name of the application as specified by the PDE JUnit // launcher. // If no application is specified, the 3.0 default workbench application // is returned. IExtension extension = Platform.getExtensionRegistry().getExtension(Platform.PI_RUNTIME, Platform.PT_APPLICATIONS, "org.eclipse.e4.ui.workbench.swt.E4Application"); //$NON-NLS-1$ Assert.isNotNull(extension); // If the extension does not have the correct grammar, return null. // Otherwise, return the application object. try { IConfigurationElement[] elements = extension.getConfigurationElements(); if (elements.length > 0) { IConfigurationElement[] runs = elements[0].getChildren("run"); //$NON-NLS-1$ if (runs.length > 0) { Object runnable; runnable = runs[0].createExecutableExtension("class");//$NON-NLS-1$ if (runnable instanceof IPlatformRunnable || runnable instanceof IApplication) return runnable; } } } catch (CoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * Creates the <code>Display</code> to be used by the workbench. * * @return the display */ public static Display createDisplay() { // setup the application name used by SWT to lookup resources on some // platforms String applicationName = WorkbenchPlugin.getDefault().getAppName(); if (applicationName != null) { Display.setAppName(applicationName); } // create the display Display newDisplay = Display.getCurrent(); if (newDisplay == null) { if (Policy.DEBUG_SWT_GRAPHICS || Policy.DEBUG_SWT_DEBUG) { DeviceData data = new DeviceData(); if (Policy.DEBUG_SWT_GRAPHICS) { data.tracking = true; } if (Policy.DEBUG_SWT_DEBUG) { data.debug = true; } newDisplay = new Display(data); } else { newDisplay = new Display(); } } // workaround for 1GEZ9UR and 1GF07HN newDisplay.setWarnings(false); // Set the priority higher than normal so as to be higher // than the JobManager. Thread.currentThread().setPriority(Math.min(Thread.MAX_PRIORITY, Thread.NORM_PRIORITY + 1)); initializeImages(); return newDisplay; } /** * Create the splash wrapper and set it to work. * * @since 3.3 */ private void createSplashWrapper() { final Display display = getDisplay(); String splashLoc = System.getProperty("org.eclipse.equinox.launcher.splash.location"); //$NON-NLS-1$ final Image background = loadImage(splashLoc); SafeRunnable run = new SafeRunnable() { @Override public void run() throws Exception { if (!WorkbenchPlugin.isSplashHandleSpecified()) { createSplash = false; return; } // create the splash getSplash(); if (splash == null) { createSplash = false; return; } Shell splashShell = splash.getSplash(); if (splashShell == null) { splashShell = WorkbenchPlugin.getSplashShell(display); if (splashShell == null) return; if (background != null) splashShell.setBackgroundImage(background); } Dictionary properties = new Hashtable(); properties.put(Constants.SERVICE_RANKING, Integer.valueOf(Integer.MAX_VALUE)); BundleContext context = WorkbenchPlugin.getDefault().getBundleContext(); final ServiceRegistration registration[] = new ServiceRegistration[1]; StartupMonitor startupMonitor = new StartupMonitor() { @Override public void applicationRunning() { if (background != null) background.dispose(); registration[0].unregister(); // unregister ourself if (splash != null) splash.dispose(); WorkbenchPlugin.unsetSplashShell(display); // fire part visibility events now that we're up for (IWorkbenchWindow window : getWorkbenchWindows()) { IWorkbenchPage page = window.getActivePage(); if (page != null) { ((WorkbenchPage) page).fireInitialPartVisibilityEvents(); } } } @Override public void update() { // do nothing - we come into the picture far too late // for this to be relevant } }; registration[0] = context.registerService(StartupMonitor.class.getName(), startupMonitor, properties); splash.init(splashShell); } @Override public void handleException(Throwable e) { StatusManager.getManager().handle( StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH, "Could not instantiate splash", e)); //$NON-NLS-1$ createSplash = false; splash = null; if (background != null) background.dispose(); } }; SafeRunner.run(run); } /** * Load an image from a filesystem path. * * @param splashLoc * the location to load from * @return the image or <code>null</code> * @since 3.3 */ private Image loadImage(String splashLoc) { Image background = null; if (splashLoc != null) { try (InputStream input = new BufferedInputStream(new FileInputStream(splashLoc)) ){ background = new Image(display, input); } catch (SWTException | IOException e) { StatusManager.getManager().handle(StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH, e)); } } return background; } /** * Return the splash handler for this application. If none is specifically * provided the default Eclipse implementation is returned. * * @return the splash handler for this application or <code>null</code> * @since 3.3 */ private static AbstractSplashHandler getSplash() { if (!createSplash) return null; if (splash == null) { IProduct product = Platform.getProduct(); if (product != null) splash = SplashHandlerFactory.findSplashHandlerFor(product); if (splash == null) splash = new EclipseSplashHandler(); } return splash; } /** * Returns the testable object facade, for use by the test harness. * * @return the testable object facade * @since 3.0 */ public static WorkbenchTestable getWorkbenchTestable() { if (testableObject == null) { testableObject = new WorkbenchTestable(); } return testableObject; } @Override public void addWorkbenchListener(IWorkbenchListener listener) { workbenchListeners.add(listener); } @Override public void removeWorkbenchListener(IWorkbenchListener listener) { workbenchListeners.remove(listener); } /** * Fire workbench preShutdown event, stopping at the first one to veto * * @param forced * flag indicating whether the shutdown is being forced * @return <code>true</code> to allow the workbench to proceed with * shutdown, <code>false</code> to veto a non-forced shutdown * @since 3.2 */ boolean firePreShutdown(final boolean forced) { for (final IWorkbenchListener l : workbenchListeners) { final boolean[] result = new boolean[] { false }; SafeRunnable.run(new SafeRunnable() { @Override public void run() { result[0] = l.preShutdown(Workbench.this, forced); } }); if (!result[0]) { return false; } } return true; } /** * Fire workbench postShutdown event. * * @since 3.2 */ void firePostShutdown() { for (final IWorkbenchListener l : workbenchListeners) { SafeRunnable.run(new SafeRunnable() { @Override public void run() { l.postShutdown(Workbench.this); } }); } } @Override public void addWindowListener(IWindowListener l) { addListenerObject(l); } @Override public void removeWindowListener(IWindowListener l) { removeListenerObject(l); } /** * Fire window opened event. * * @param window * The window which just opened; should not be <code>null</code>. */ protected void fireWindowOpened(final IWorkbenchWindow window) { Object list[] = getListeners(); for (Object element : list) { final IWindowListener l = (IWindowListener) element; SafeRunner.run(new SafeRunnable() { @Override public void run() { l.windowOpened(window); } }); } } /** * Fire window closed event. * * @param window * The window which just closed; should not be <code>null</code>. */ protected void fireWindowClosed(final IWorkbenchWindow window) { Object list[] = getListeners(); for (Object element : list) { final IWindowListener l = (IWindowListener) element; SafeRunner.run(new SafeRunnable() { @Override public void run() { l.windowClosed(window); } }); } } /** * Fire window activated event. * * @param window * The window which was just activated; should not be * <code>null</code>. */ protected void fireWindowActivated(final IWorkbenchWindow window) { Object list[] = getListeners(); for (Object element : list) { final IWindowListener l = (IWindowListener) element; SafeRunner.run(new SafeRunnable() { @Override public void run() { l.windowActivated(window); } }); } } /** * Fire window deactivated event. * * @param window * The window which was just deactivated; should not be * <code>null</code>. */ protected void fireWindowDeactivated(final IWorkbenchWindow window) { Object list[] = getListeners(); for (Object element : list) { final IWindowListener l = (IWindowListener) element; SafeRunner.run(new SafeRunnable() { @Override public void run() { l.windowDeactivated(window); } }); } } /** * Closes the workbench. Assumes that the busy cursor is active. * * @param force * true if the close is mandatory, and false if the close is * allowed to fail * @return true if the close succeeded, and false otherwise */ private boolean busyClose(final boolean force) { // Fire an E4 lifecycle notification UIEvents.publishEvent(UIEvents.UILifeCycle.APP_SHUTDOWN_STARTED, application); // notify the advisor of preShutdown and allow it to veto if not forced isClosing = advisor.preShutdown(); if (!force && !isClosing) { return false; } // notify regular workbench clients of preShutdown and allow them to // veto if not forced isClosing = firePreShutdown(force); if (!force && !isClosing) { return false; } // save any open editors if they are dirty isClosing = saveAllEditors(!force, true); if (!force && !isClosing) { return false; } // stop the workbench auto-save job so it can't conflict with shutdown if(autoSaveJob != null) { autoSaveJob.cancel(); autoSaveJob = null; } boolean closeEditors = !force && PrefUtil.getAPIPreferenceStore().getBoolean( IWorkbenchPreferenceConstants.CLOSE_EDITORS_ON_EXIT); if (closeEditors) { SafeRunner.run(new SafeRunnable() { @Override public void run() { IWorkbenchWindow windows[] = getWorkbenchWindows(); for (IWorkbenchWindow window : windows) { IWorkbenchPage pages[] = window.getPages(); for (IWorkbenchPage page : pages) { isClosing = isClosing && page.closeAllEditors(false); } } } }); if (!force && !isClosing) { return false; } } // persist editor inputs and close editors that can't be persisted // also persists views persist(true); if (!force && !isClosing) { return false; } SafeRunner.run(new SafeRunnable(WorkbenchMessages.ErrorClosing) { @Override public void run() { if (isClosing || force) { // isClosing = windowManager.close(); E4Util.unsupported("Need to close since no windowManager"); //$NON-NLS-1$ MWindow selectedWindow = application.getSelectedElement(); WorkbenchWindow selected = null; for (IWorkbenchWindow window : getWorkbenchWindows()) { WorkbenchWindow ww = (WorkbenchWindow) window; if (ww.getModel() == selectedWindow) { selected = ww; } else { ((WorkbenchWindow) window).close(false); } } if (selected != null) { selected.close(false); } windowsClosed = true; } } }); if (!force && !isClosing) { return false; } shutdown(); IPresentationEngine engine = application.getContext().get(IPresentationEngine.class); engine.stop(); //System.err.println("stop()"); //$NON-NLS-1$ runEventLoop = false; return true; } /** * Saves the state of the workbench in the same way that closing the it * would. Can be called while the editor is running so that if it crashes * the workbench state can be recovered. * * @param shutdown * If true, will close any editors that cannot be persisted. Will * also skip saving the model to the disk since that is done * later in shutdown. */ private void persist(final boolean shutdown) { // persist editors that can be and possibly close the others SafeRunner.run(new SafeRunnable() { @Override public void run() { IWorkbenchWindow windows[] = getWorkbenchWindows(); for (IWorkbenchWindow window : windows) { IWorkbenchPage pages[] = window.getPages(); for (IWorkbenchPage page : pages) { List<EditorReference> editorReferences = ((WorkbenchPage) page) .getInternalEditorReferences(); List<EditorReference> referencesToClose = new ArrayList<>(); for (EditorReference reference : editorReferences) { IEditorPart editor = reference.getEditor(false); if (editor != null && !reference.persist() && shutdown) { referencesToClose.add(reference); } } if (shutdown) { for (EditorReference reference : referencesToClose) { ((WorkbenchPage) page).closeEditor(reference); } } } } } }); // persist workbench state if (getWorkbenchConfigurer().getSaveAndRestore()) { SafeRunner.run(new SafeRunnable() { @Override public void run() { persistWorkbenchState(); } @Override public void handleException(Throwable e) { String message; if (e.getMessage() == null) { message = WorkbenchMessages.ErrorClosingNoArg; } else { message = NLS.bind(WorkbenchMessages.ErrorClosingOneArg, e.getMessage()); } if (!MessageDialog.openQuestion(null, WorkbenchMessages.Error, message)) { isClosing = false; } } }); } // persist view states SafeRunner.run(new SafeRunnable() { @Override public void run() { IWorkbenchWindow windows[] = getWorkbenchWindows(); for (IWorkbenchWindow window : windows) { IWorkbenchPage pages[] = window.getPages(); for (IWorkbenchPage page : pages) { IViewReference[] references = page.getViewReferences(); for (IViewReference reference : references) { if (reference.getView(false) != null) { ((ViewReference) reference).persist(); } } } } } }); // now that we have updated the model, save it to workbench.xmi // skip this during shutdown to be efficient since it is done again // later if (!shutdown) { persistWorkbenchModel(); } } private boolean detectWorkbenchCorruption(MApplication application) { if (application.getChildren().isEmpty()) { WorkbenchPlugin.log( "When auto-saving the workbench model, there were no top-level windows. " //$NON-NLS-1$ + " Skipped saving the model.", //$NON-NLS-1$ new Exception()); // log a stack trace to assist debugging return true; } return false; } /** * Copy the model, clean it up and write it out to workbench.xmi. Called as * part of persist(false) during auto-save. */ private void persistWorkbenchModel() { if (Job.getJobManager().find(WORKBENCH_AUTO_SAVE_JOB).length > 0) { return; } final MApplication appCopy = (MApplication) EcoreUtil.copy((EObject) application); if (detectWorkbenchCorruption(appCopy)) { return; } final IModelResourceHandler handler = e4Context.get(IModelResourceHandler.class); Job cleanAndSaveJob = new Job(WORKBENCH_AUTO_SAVE_BACKGROUND_JOB) { @Override protected IStatus run(IProgressMonitor monitor) { final Resource res = handler.createResourceWithApp(appCopy); cleanUpCopy(appCopy, e4Context); try { if (!detectWorkbenchCorruption((MApplication) res.getContents().get(0))) { res.save(null); } } catch (IOException e) { // Just auto-save, we don't really care } finally { res.unload(); res.getResourceSet().getResources().remove(res); } return Status.OK_STATUS; } @Override public boolean belongsTo(Object family) { return WORKBENCH_AUTO_SAVE_JOB.equals(family); } }; cleanAndSaveJob.setPriority(Job.SHORT); cleanAndSaveJob.setSystem(true); cleanAndSaveJob.schedule(); } private static void cleanUpCopy(MApplication appCopy, IEclipseContext context) { // clean up all trim bars that come from trim bar contributions // the trim elements that need to be removed are stored in the trimBar. setSearchContribution(appCopy, false); EModelService modelService = context.get(EModelService.class); List<MWindow> windows = modelService.findElements(appCopy, null, MWindow.class, null); for (MWindow window : windows) { if (window instanceof MTrimmedWindow) { MTrimmedWindow trimmedWindow = (MTrimmedWindow) window; // clean up the main menu to avoid duplicate menu items window.setMainMenu(null); // clean up trim bars created through contributions // to avoid duplicate toolbars for (MTrimBar trimBar : trimmedWindow.getTrimBars()) { cleanUpTrimBar(trimBar); } } } appCopy.getMenuContributions().clear(); appCopy.getToolBarContributions().clear(); appCopy.getTrimContributions().clear(); List<MPart> parts = modelService.findElements(appCopy, null, MPart.class, null); for (MPart part : parts) { for (MMenu menu : part.getMenus()) { menu.getChildren().clear(); } MToolBar tb = part.getToolbar(); if (tb != null) { tb.getChildren().clear(); } } } private static void cleanUpTrimBar(MTrimBar element) { for (MTrimElement child : element.getPendingCleanup()) { element.getChildren().remove(child); } element.getPendingCleanup().clear(); } @Override public boolean saveAllEditors(boolean confirm) { return saveAllEditors(confirm, false); } private boolean saveAllEditors(boolean confirm, boolean closing) { IWorkbenchWindow[] windows = getWorkbenchWindows(); if (windows.length == 0) { return true; } Set<IWorkbenchPart> dirtyParts = new HashSet<>(); for (IWorkbenchWindow window : windows) { WorkbenchPage page = (WorkbenchPage) window.getActivePage(); if (page != null) { Collections.addAll(dirtyParts, page.getDirtyWorkbenchParts()); } } IWorkbenchWindow activeWindow = getActiveWorkbenchWindow(); if (activeWindow == null) { activeWindow = windows[0]; } return WorkbenchPage.saveAll(new ArrayList<>(dirtyParts), confirm, closing, true, activeWindow, activeWindow); } @Override public boolean close() { return close(PlatformUI.RETURN_OK, false); } /** * Closes the workbench, returning the given return code from the run * method. If forced, the workbench is closed no matter what. * * @param returnCode * {@link PlatformUI#RETURN_OK RETURN_OK}for normal exit; * {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the * workbench was terminated with a call to * {@link IWorkbench#restart IWorkbench.restart}; * {@link PlatformUI#RETURN_EMERGENCY_CLOSE} for an emergency * shutdown {@link PlatformUI#RETURN_UNSTARTABLE * RETURN_UNSTARTABLE}if the workbench could not be started; * other values reserved for future use * * @param force * true to force the workbench close, and false for a "soft" * close that can be canceled * @return true if the close was successful, and false if the close was * canceled */ /* package */ boolean close(int returnCode, final boolean force) { this.returnCode = returnCode; final boolean[] ret = new boolean[1]; BusyIndicator.showWhile(null, () -> ret[0] = busyClose(force)); return ret[0]; } @Override public IWorkbenchWindow getActiveWorkbenchWindow() { // Return null if called from a non-UI thread. // This is not spec'ed behaviour and is misleading, however this is how // it // worked in 2.1 and we cannot change it now. // For more details, see [Bug 57384] [RCP] Main window not active on // startup if (Display.getCurrent() == null || !initializationDone) { return null; } // the source providers try to update again during shutdown if (windowsClosed) { return null; } // rendering engine not available, can't make workbench windows, see bug // 320932 if (e4Context.get(IPresentationEngine.class) == null) { return null; } MWindow activeWindow = application.getSelectedElement(); if ((activeWindow == null || activeWindow.getWidget() == null) && !application.getChildren().isEmpty()) { activeWindow = application.getChildren().get(0); } // We can't return a window with no widget...it's in the process // of closing...see Bug 379717 if (activeWindow == null || (activeWindow != null && activeWindow.getWidget() == null)) { return null; } // search for existing IWorkbenchWindow IWorkbenchWindow iWorkbenchWindow = activeWindow.getContext().get(IWorkbenchWindow.class); if (iWorkbenchWindow != null) { return iWorkbenchWindow; } // otherwise create new IWorkbenchWindow instance return createWorkbenchWindow(getDefaultPageInput(), getPerspectiveRegistry() .findPerspectiveWithId(getPerspectiveRegistry().getDefaultPerspective()), activeWindow, false); } IWorkbenchWindow createWorkbenchWindow(IAdaptable input, IPerspectiveDescriptor descriptor, MWindow window, boolean newWindow) { IEclipseContext windowContext = window.getContext(); if (windowContext == null) { windowContext = E4Workbench.initializeContext(e4Context, window); } WorkbenchWindow result = (WorkbenchWindow) windowContext.get(IWorkbenchWindow.class); if (result == null) { if (windowBeingCreated != null) return windowBeingCreated; result = new WorkbenchWindow(input, descriptor); windowBeingCreated = result; try { if (newWindow) { Point size = result.getWindowConfigurer().getInitialSize(); window.setWidth(size.x); window.setHeight(size.y); application.getChildren().add(window); application.setSelectedElement(window); } ContextInjectionFactory.inject(result, windowContext); windowContext.set(IWorkbenchWindow.class, result); } finally { windowBeingCreated = null; } if (application.getSelectedElement() == window) { application.getContext().set(ISources.ACTIVE_WORKBENCH_WINDOW_NAME, result); application.getContext().set(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME, result.getShell()); } fireWindowOpened(result); result.fireWindowOpened(); } return result; } /* * Returns the editor history. */ public EditorHistory getEditorHistory() { if (editorHistory == null) { editorHistory = new EditorHistory(); } return editorHistory; } @Override public IEditorRegistry getEditorRegistry() { return WorkbenchPlugin.getDefault().getEditorRegistry(); } @Override public IWorkbenchOperationSupport getOperationSupport() { return WorkbenchPlugin.getDefault().getOperationSupport(); } @Override public IPerspectiveRegistry getPerspectiveRegistry() { return WorkbenchPlugin.getDefault().getPerspectiveRegistry(); } @Override public PreferenceManager getPreferenceManager() { return WorkbenchPlugin.getDefault().getPreferenceManager(); } @Override public IPreferenceStore getPreferenceStore() { return WorkbenchPlugin.getDefault().getPreferenceStore(); } @Override public ISharedImages getSharedImages() { return WorkbenchPlugin.getDefault().getSharedImages(); } @Override public int getWorkbenchWindowCount() { return getWorkbenchWindows().length; } @Override public IWorkbenchWindow[] getWorkbenchWindows() { List<IWorkbenchWindow> windows = new ArrayList<>(); for (MWindow window : application.getChildren()) { IEclipseContext context = window.getContext(); if (context != null) { IWorkbenchWindow wwindow = (IWorkbenchWindow) context.get(IWorkbenchWindow.class .getName()); if (wwindow != null) { windows.add(wwindow); } } } return windows.toArray(new IWorkbenchWindow[windows.size()]); } @Override public IWorkingSetManager getWorkingSetManager() { return WorkbenchPlugin.getDefault().getWorkingSetManager(); } /** * {@inheritDoc} */ @Override public ILocalWorkingSetManager createLocalWorkingSetManager() { return new LocalWorkingSetManager(WorkbenchPlugin.getDefault().getBundleContext()); } /** * Initializes the workbench now that the display is created. * * @return true if init succeeded. */ private boolean init() { // setup debug mode if required. if (WorkbenchPlugin.getDefault().isDebugging()) { WorkbenchPlugin.DEBUG = true; ModalContext.setDebugMode(true); } // Set up the JFace preference store JFaceUtil.initializeJFacePreferences(); // create workbench window manager // windowManager = new WindowManager(); // TODO compat: I've removed the window manager, now what // TODO Correctly order service initialization // there needs to be some serious consideration given to // the services, and hooking them up in the correct order e4Context.set("org.eclipse.core.runtime.Platform", Platform.class); //$NON-NLS-1$ final EvaluationService evaluationService = new EvaluationService(e4Context); StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { serviceLocator.registerService(IEvaluationService.class, evaluationService); } }); initializeLazyServices(); // Initialize the activity support. activityHelper = ActivityPersistanceHelper.getInstance(); StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { WorkbenchImages.getImageRegistry(); } }); initializeE4Services(); IIntroRegistry introRegistry = WorkbenchPlugin.getDefault().getIntroRegistry(); if (introRegistry.getIntroCount() > 0) { IProduct product = Platform.getProduct(); if (product != null) { introDescriptor = (IntroDescriptor) introRegistry.getIntroForProduct(product .getId()); } } initializeDefaultServices(); initializeFonts(); initializeColors(); initializeApplicationColors(); // now that the workbench is sufficiently initialized, let the advisor // have a turn. StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { advisor.internalBasicInitialize(getWorkbenchConfigurer()); } }); // configure use of color icons in toolbars boolean useColorIcons = PrefUtil.getInternalPreferenceStore().getBoolean( IPreferenceConstants.COLOR_ICONS); ActionContributionItem.setUseColorIconsInToolbars(useColorIcons); // initialize workbench single-click vs double-click behavior initializeSingleClickOption(); initializeGlobalization(); initializeNLExtensions(); initializeWorkbenchImages(); StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { ((GrabFocus) Tweaklets.get(GrabFocus.KEY)).init(getDisplay()); } }); // attempt to restore a previous workbench state try { UIStats.start(UIStats.RESTORE_WORKBENCH, "Workbench"); //$NON-NLS-1$ final boolean bail[] = new boolean[1]; StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() throws Throwable { advisor.preStartup(); // TODO compat: open the windows here/instantiate the model // TODO compat: instantiate the WW around the model initializationDone = true; if (isClosing() || !advisor.openWindows()) { // if (isClosing()) { bail[0] = true; } restoreWorkbenchState(); } }); if (bail[0]) return false; } finally { UIStats.end(UIStats.RESTORE_WORKBENCH, this, "Workbench"); //$NON-NLS-1$ } // forceOpenPerspective(); return true; } /** * */ private void initializeWorkbenchImages() { StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { WorkbenchImages.getDescriptors(); } }); } /** * Establishes the relationship between JFace actions and the command * manager. */ private void initializeCommandResolver() { ExternalActionManager.getInstance().setCallback( new CommandCallback(bindingManager, commandManager, commandId -> workbenchActivitySupport.getActivityManager().getIdentifier( commandId).isEnabled(), action -> !(action instanceof CommandAction))); } /** * Initialize colors defined by the new colorDefinitions extension point. * Note this will be rolled into initializeColors() at some point. * * @since 3.0 */ private void initializeApplicationColors() { StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { ColorDefinition[] colorDefinitions = WorkbenchPlugin.getDefault() .getThemeRegistry().getColors(); ThemeElementHelper.populateRegistry(getThemeManager().getCurrentTheme(), colorDefinitions, PrefUtil.getInternalPreferenceStore()); } }); } void initializeSingleClickOption() { IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); boolean openOnSingleClick = store.getBoolean(IPreferenceConstants.OPEN_ON_SINGLE_CLICK); boolean selectOnHover = store.getBoolean(IPreferenceConstants.SELECT_ON_HOVER); boolean openAfterDelay = store.getBoolean(IPreferenceConstants.OPEN_AFTER_DELAY); int singleClickMethod = openOnSingleClick ? OpenStrategy.SINGLE_CLICK : OpenStrategy.DOUBLE_CLICK; if (openOnSingleClick) { if (selectOnHover) { singleClickMethod |= OpenStrategy.SELECT_ON_HOVER; } if (openAfterDelay) { singleClickMethod |= OpenStrategy.ARROW_KEYS_OPEN; } } OpenStrategy.setOpenMethod(singleClickMethod); } private void initializeGlobalization() { IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); if (!store.isDefault(IPreferenceConstants.BIDI_SUPPORT)) { BidiUtils.setBidiSupport(store.getBoolean(IPreferenceConstants.BIDI_SUPPORT)); } if (!store.isDefault(IPreferenceConstants.TEXT_DIRECTION)) { BidiUtils.setTextDirection(store.getString(IPreferenceConstants.TEXT_DIRECTION)); } } private void initializeNLExtensions() { IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); if (!store.isDefault(IPreferenceConstants.NL_EXTENSIONS)) { String nlExtensions = store.getString(IPreferenceConstants.NL_EXTENSIONS); ULocale.setDefault(Category.FORMAT, new ULocale(ULocale.getDefault(Category.FORMAT) .getBaseName() + nlExtensions)); } } /* * Initializes the workbench fonts with the stored values. */ private void initializeFonts() { StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { FontDefinition[] fontDefinitions = WorkbenchPlugin.getDefault().getThemeRegistry() .getFonts(); ThemeElementHelper.populateRegistry(getThemeManager().getCurrentTheme(), fontDefinitions, PrefUtil.getInternalPreferenceStore()); final IPropertyChangeListener themeToPreferencesFontSynchronizer = event -> { if (event.getNewValue() instanceof FontData[]) { FontData[] fontData = (FontData[]) event.getNewValue(); PrefUtil.getInternalPreferenceStore().setValue(event.getProperty(), PreferenceConverter.getStoredRepresentation(fontData)); } }; getThemeManager().getCurrentTheme().getFontRegistry().addListener(themeToPreferencesFontSynchronizer); getThemeManager().addPropertyChangeListener(event -> { if (IThemeManager.CHANGE_CURRENT_THEME.equals(event.getProperty())) { Object oldValue = event.getOldValue(); if (oldValue != null && oldValue instanceof ITheme) { ((ITheme) oldValue).removePropertyChangeListener(themeToPreferencesFontSynchronizer); } Object newValue = event.getNewValue(); if (newValue != null && newValue instanceof ITheme) { ((ITheme) newValue).addPropertyChangeListener(themeToPreferencesFontSynchronizer); } } }); } }); } /* * Initialize the workbench images. * * @param windowImages An array of the descriptors of the images to be used * in the corner of each window, or <code>null</code> if none. It is * expected that the array will contain the same icon, rendered at different * sizes. * * @since 3.0 */ private static void initializeImages() { ImageDescriptor[] windowImages = WorkbenchPlugin.getDefault().getWindowImages(); if (windowImages == null) { return; } Image[] images = new Image[windowImages.length]; for (int i = 0; i < windowImages.length; ++i) { images[i] = windowImages[i].createImage(); } Window.setDefaultImages(images); } /* * Take the workbenches' images out of the shared registry. * * @since 3.0 */ private void uninitializeImages() { WorkbenchImages.dispose(); Image[] images = Window.getDefaultImages(); Window.setDefaultImage(null); for (Image image : images) { image.dispose(); } } /* * Initialize the workbench colors. * * @since 3.0 */ private void initializeColors() { StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { WorkbenchColors.startup(); } }); } @Override public boolean isClosing() { return isClosing; } private final void initializeE4Services() { // track the workbench preference and update the eclipse context with // the new value IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore(); preferenceStore.addPropertyChangeListener(event -> { if (IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS.equals(event.getProperty())) { Object o = event.getNewValue(); if (o instanceof Boolean) { // Boolean if notified after the preference page has // been closed e4Context.set(IPresentationEngine.ANIMATIONS_ENABLED, o); } else if (o instanceof String) { // String if notified via an import of the preference e4Context.set(IPresentationEngine.ANIMATIONS_ENABLED, Boolean.parseBoolean((String) event.getNewValue())); } } }); eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_CHILDREN, event -> { if (application == event.getProperty(UIEvents.EventTags.ELEMENT)) { if (UIEvents.isREMOVE(event)) { for (Object removed : UIEvents.asIterable(event, UIEvents.EventTags.OLD_VALUE)) { MWindow window = (MWindow) removed; IEclipseContext windowContext = window.getContext(); if (windowContext != null) { IWorkbenchWindow wwindow = windowContext.get(IWorkbenchWindow.class); if (wwindow != null) { fireWindowClosed(wwindow); } } } } } }); eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT, event -> { if (application == event.getProperty(UIEvents.EventTags.ELEMENT)) { if (UIEvents.EventTypes.SET.equals(event.getProperty(UIEvents.EventTags.TYPE))) { MWindow window = (MWindow) event.getProperty(UIEvents.EventTags.NEW_VALUE); if (window != null) { IWorkbenchWindow wwindow = window.getContext().get(IWorkbenchWindow.class); if (wwindow != null) { e4Context.set(ISources.ACTIVE_WORKBENCH_WINDOW_NAME, wwindow); e4Context.set(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME, wwindow.getShell()); } } } } }); // watch for parts' "toBeRendered" attribute being flipped to true, if // they need to be rendered, then they need a corresponding 3.x // reference eventBroker.subscribe(UIEvents.UIElement.TOPIC_TOBERENDERED, event -> { if (Boolean.TRUE.equals(event.getProperty(UIEvents.EventTags.NEW_VALUE))) { Object element = event.getProperty(UIEvents.EventTags.ELEMENT); if (element instanceof MPart) { MPart part = (MPart) element; createReference(part); } } }); // watch for parts' contexts being set, once they've been set, we need // to inject the ViewReference/EditorReference into the context eventBroker.subscribe(UIEvents.Context.TOPIC_CONTEXT, event -> { Object element = event.getProperty(UIEvents.EventTags.ELEMENT); if (element instanceof MPart) { MPart part = (MPart) element; IEclipseContext context = part.getContext(); if (context != null) { setReference(part, context); } } }); eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_CHILDREN, event -> { Object element = event.getProperty(UIEvents.EventTags.ELEMENT); if (!(element instanceof MApplication)) { return; } MApplication app = (MApplication) element; if (UIEvents.isREMOVE(event)) { if (app.getChildren().isEmpty()) { Object oldValue = event.getProperty(UIEvents.EventTags.OLD_VALUE); WorkbenchPlugin.log("The final top level window " + oldValue //$NON-NLS-1$ + " was just removed", new Exception()); //$NON-NLS-1$ } } }); eventBroker.subscribe(UIEvents.UIModelTopicBase + "/*", event -> { // //$NON-NLS-1$ applicationModelChanged = true; }); boolean found = false; List<MPartDescriptor> currentDescriptors = application.getDescriptors(); for (MPartDescriptor desc : currentDescriptors) { // do we have a matching descriptor? if (desc.getElementId().equals(CompatibilityEditor.MODEL_ELEMENT_ID)) { found = true; break; } } if (!found) { MPartDescriptor descriptor = org.eclipse.e4.ui.model.application.descriptor.basic.impl.BasicFactoryImpl.eINSTANCE .createPartDescriptor(); descriptor.getTags().add("Editor"); //$NON-NLS-1$ descriptor.setCloseable(true); descriptor.setAllowMultiple(true); descriptor.setElementId(CompatibilityEditor.MODEL_ELEMENT_ID); descriptor.setContributionURI(CompatibilityPart.COMPATIBILITY_EDITOR_URI); descriptor.setCategory("org.eclipse.e4.primaryDataStack"); //$NON-NLS-1$ application.getDescriptors().add(descriptor); } WorkbenchPlugin.getDefault().getViewRegistry(); } /** * Returns a workbench page that will contain the specified part. If no page * can be located, one will be instantiated. * * @param part * the model part to query a parent workbench page for * @return the workbench page that contains the specified part */ private WorkbenchPage getWorkbenchPage(MPart part) { IEclipseContext context = getWindowContext(part); WorkbenchPage page = (WorkbenchPage) context.get(IWorkbenchPage.class); if (page == null) { MWindow window = context.get(MWindow.class); Workbench workbench = (Workbench) PlatformUI.getWorkbench(); workbench.openWorkbenchWindow(getDefaultPageInput(), getPerspectiveRegistry() .findPerspectiveWithId(getDefaultPerspectiveId()), window, false); page = (WorkbenchPage) context.get(IWorkbenchPage.class); } return page; } /** * Sets the 3.x reference of the specified part into its context. * * @param part * the model part that requires a 3.x part reference * @param context * the part's context */ private void setReference(MPart part, IEclipseContext context) { String uri = part.getContributionURI(); if (CompatibilityPart.COMPATIBILITY_EDITOR_URI.equals(uri)) { WorkbenchPage page = getWorkbenchPage(part); EditorReference ref = page.getEditorReference(part); if (ref == null) { // If this editor was cloned from an existing editor (as // part of a split...) then re-create a valid EditorReference // from the existing editor's ref. MPart clonedFrom = (MPart) part.getTransientData().get(EModelService.CLONED_FROM_KEY); if (clonedFrom != null && clonedFrom.getContext() != null) { EditorReference originalRef = page.getEditorReference(clonedFrom); if (originalRef != null) { IEditorInput partInput = null; String editorId = originalRef.getDescriptor().getId(); try { partInput = originalRef.getEditorInput(); } catch (PartInitException e) { System.out.println("Ooops !!!"); //$NON-NLS-1$ } ref = page.createEditorReferenceForPart(part, partInput, editorId, null); } } // Fallback code if (ref == null) { ref = createEditorReference(part, page); } } context.set(EditorReference.class, ref); } else { // Create View References for 'e4' parts as well WorkbenchPage page = getWorkbenchPage(part); ViewReference ref = page.getViewReference(part); if (ref == null) { ref = createViewReference(part, page); } context.set(ViewReference.class, ref); } } private ViewReference createViewReference(MPart part, WorkbenchPage page) { WorkbenchWindow window = (WorkbenchWindow) page.getWorkbenchWindow(); // If the partId contains a ':' then only use the substring before it to // fine the descriptor String partId = part.getElementId(); // If the id contains a ':' use the part before it as the descriptor id int colonIndex = partId.indexOf(':'); String descId = colonIndex == -1 ? partId : partId.substring(0, colonIndex); IViewDescriptor desc = window.getWorkbench().getViewRegistry().find(descId); ViewReference ref = new ViewReference(window.getModel().getContext(), page, part, (ViewDescriptor) desc); page.addViewReference(ref); return ref; } private EditorReference createEditorReference(MPart part, WorkbenchPage page) { WorkbenchWindow window = (WorkbenchWindow) page.getWorkbenchWindow(); EditorReference ref = new EditorReference(window.getModel().getContext(), page, part, null, null, null); page.addEditorReference(ref); return ref; } /** * Creates a workbench part reference for the specified part if one does not * already exist. * * @param part * the model part to create a 3.x part reference for */ private void createReference(MPart part) { String uri = part.getContributionURI(); if (CompatibilityPart.COMPATIBILITY_VIEW_URI.equals(uri)) { WorkbenchPage page = getWorkbenchPage(part); ViewReference ref = page.getViewReference(part); if (ref == null) { createViewReference(part, page); } } else if (CompatibilityPart.COMPATIBILITY_EDITOR_URI.equals(uri)) { WorkbenchPage page = getWorkbenchPage(part); EditorReference ref = page.getEditorReference(part); if (ref == null) { createEditorReference(part, page); } } } private IEclipseContext getWindowContext(MPart part) { MElementContainer<?> parent = (MElementContainer<?>) ((EObject) part).eContainer(); while (!(parent instanceof MWindow)) { parent = (MElementContainer<?>) ((EObject) parent).eContainer(); // parent.getParent(); } return ((MWindow) parent).getContext(); } private final void initializeLazyServices() { e4Context.set(IExtensionTracker.class.getName(), new ContextFunction() { @Override public Object compute(IEclipseContext context, String contextKey) { if (tracker == null) { tracker = new UIExtensionTracker(getDisplay()); } return tracker; } }); e4Context.set(IWorkbenchActivitySupport.class.getName(), new ContextFunction() { @Override public Object compute(IEclipseContext context, String contextKey) { if (workbenchActivitySupport == null) { workbenchActivitySupport = new WorkbenchActivitySupport(); } return workbenchActivitySupport; } }); e4Context.set(IProgressService.class.getName(), new ContextFunction() { @Override public Object compute(IEclipseContext context, String contextKey) { return ProgressManager.getInstance(); } }); WorkbenchPlugin.getDefault().initializeContext(e4Context); } private ArrayList<MCommand> commandsToRemove = new ArrayList<>(); private ArrayList<MCategory> categoriesToRemove = new ArrayList<>(); private CommandService initializeCommandService(IEclipseContext appContext) { CommandService service = new CommandService(commandManager, appContext); appContext.set(ICommandService.class, service); appContext.set(IUpdateService.class, service); service.readRegistry(); return service; } private Map<String, MBindingContext> bindingContexts = new HashMap<>(); public MBindingContext getBindingContext(String id) { // cache MBindingContext result = bindingContexts.get(id); if (result == null) { // search result = searchContexts(id, application.getRootContext()); if (result == null) { // create result = MCommandsFactory.INSTANCE.createBindingContext(); result.setElementId(id); result.setName("Auto::" + id); //$NON-NLS-1$ application.getRootContext().add(result); } if (result != null) { bindingContexts.put(id, result); } } return result; } /** * @param id * @param rootContext * @return */ private MBindingContext searchContexts(String id, List<MBindingContext> rootContext) { for (MBindingContext context : rootContext) { if (context.getElementId().equals(id)) { return context; } MBindingContext result = searchContexts(id, context.getChildren()); if (result != null) { return result; } } return null; } private void defineBindingTable(String id) { List<MBindingTable> bindingTables = application.getBindingTables(); if (contains(bindingTables, id)) { return; } if (WorkbenchPlugin.getDefault().isDebugging()) { WorkbenchPlugin.log("Defining a binding table: " + id); //$NON-NLS-1$ } MBindingTable bt = CommandsFactoryImpl.eINSTANCE.createBindingTable(); bt.setBindingContext(getBindingContext(id)); bindingTables.add(bt); } /** * @param bindingTables * @param id * @return true if this BT already exists */ private boolean contains(List<MBindingTable> bindingTables, String id) { for (MBindingTable bt : bindingTables) { if (id.equals(bt.getBindingContext().getElementId())) { return true; } } return false; } /** * Initializes all of the default services for the workbench. For * initializing the command-based services, this also parses the registry * and hooks up all the required listeners. */ private final void initializeDefaultServices() { final IContributionService contributionService = new ContributionService(getAdvisor()); serviceLocator.registerService(IContributionService.class, contributionService); // TODO Correctly order service initialization // there needs to be some serious consideration given to // the services, and hooking them up in the correct order final IEvaluationService evaluationService = serviceLocator.getService(IEvaluationService.class); StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { serviceLocator.registerService(ISaveablesLifecycleListener.class, new SaveablesList()); } }); /* * Phase 1 of the initialization of commands. When this phase completes, * all the services and managers will exist, and be accessible via the * getService(Object) method. */ StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { Command.DEBUG_COMMAND_EXECUTION = Policy.DEBUG_COMMANDS; commandManager = e4Context.get(CommandManager.class); } }); final CommandService[] commandService = new CommandService[1]; StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { commandService[0] = initializeCommandService(e4Context); } }); StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { ContextManager.DEBUG = Policy.DEBUG_CONTEXTS; contextManager = e4Context.get(ContextManager.class); } }); IContextService cxs = ContextInjectionFactory.make(ContextService.class, e4Context); final IContextService contextService = cxs; StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { contextManager.addContextManagerListener(contextManagerEvent -> { if (contextManagerEvent.isContextChanged()) { String id = contextManagerEvent.getContextId(); if (id != null) { defineBindingTable(id); } } }); EContextService ecs = e4Context.get(EContextService.class); ecs.activateContext(IContextService.CONTEXT_ID_DIALOG_AND_WINDOW); } }); serviceLocator.registerService(IContextService.class, contextService); final IBindingService[] bindingService = new BindingService[1]; StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { BindingManager.DEBUG = Policy.DEBUG_KEY_BINDINGS; bindingManager = e4Context.get(BindingManager.class); bindingService[0] = ContextInjectionFactory.make( BindingService.class, e4Context); } }); // bindingService[0].readRegistryAndPreferences(commandService[0]); serviceLocator.registerService(IBindingService.class, bindingService[0]); final CommandImageManager commandImageManager = new CommandImageManager(); final CommandImageService commandImageService = new CommandImageService(commandImageManager, commandService[0]); commandImageService.readRegistry(); serviceLocator.registerService(ICommandImageService.class, commandImageService); final WorkbenchMenuService menuService = new WorkbenchMenuService(serviceLocator, e4Context); serviceLocator.registerService(IMenuService.class, menuService); // the service must be registered before it is initialized - its // initialization uses the service locator to address a dependency on // the menu service StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { menuService.readRegistry(); } }); /* * Phase 2 of the initialization of commands. The source providers that * the workbench provides are creating and registered with the above * services. These source providers notify the services when particular * pieces of workbench state change. */ final SourceProviderService sourceProviderService = new SourceProviderService(serviceLocator); serviceLocator.registerService(ISourceProviderService.class, sourceProviderService); StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { // this currently instantiates all players ... sigh sourceProviderService.readRegistry(); ISourceProvider[] sp = sourceProviderService.getSourceProviders(); for (int i = 0; i < sp.length; i++) { evaluationService.addSourceProvider(sp[i]); if (!(sp[i] instanceof ActiveContextSourceProvider)) { contextService.addSourceProvider(sp[i]); } } } }); StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { // these guys are need to provide the variables they say // they source FocusControlSourceProvider focusControl = (FocusControlSourceProvider) sourceProviderService .getSourceProvider(ISources.ACTIVE_FOCUS_CONTROL_ID_NAME); serviceLocator.registerService(IFocusService.class, focusControl); menuSourceProvider = (MenuSourceProvider) sourceProviderService .getSourceProvider(ISources.ACTIVE_MENU_NAME); } }); /* * Phase 3 of the initialization of commands. This handles the creation * of wrappers for legacy APIs. By the time this phase completes, any * code trying to access commands through legacy APIs should work. */ final IHandlerService[] handlerService = new IHandlerService[1]; StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { handlerService[0] = new LegacyHandlerService(e4Context); e4Context.set(IHandlerService.class, handlerService[0]); handlerService[0].readRegistry(); } }); workbenchContextSupport = new WorkbenchContextSupport(this, contextManager); workbenchCommandSupport = new WorkbenchCommandSupport(bindingManager, commandManager, contextManager, handlerService[0]); initializeCommandResolver(); // addWindowListener(windowListener); bindingManager.addBindingManagerListener(bindingManagerListener); serviceLocator.registerService(ISelectionConversionService.class, new SelectionConversionService()); backForwardListener = createBackForwardListener(); StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() { getDisplay().addFilter(SWT.MouseDown, backForwardListener); } }); } private Listener createBackForwardListener() { return event -> { String commandId; switch (event.button) { case 4: case 8: commandId = IWorkbenchCommandConstants.NAVIGATE_BACKWARD_HISTORY; break; case 5: case 9: commandId = IWorkbenchCommandConstants.NAVIGATE_FORWARD_HISTORY; break; default: return; } final IHandlerService handlerService = getService(IHandlerService.class); try { handlerService.executeCommand(commandId, event); event.doit = false; } catch (NotDefinedException e1) { // regular condition; do nothing } catch (NotEnabledException e2) { // regular condition; do nothing } catch (NotHandledException e3) { // regular condition; do nothing } catch (ExecutionException ex) { StatusUtil.handleStatus(ex, StatusManager.SHOW | StatusManager.LOG); } }; } /** * Returns true if the Workbench is in the process of starting. * * @return <code>true</code> if the Workbench is starting, but not yet * running the event loop. */ @Override public boolean isStarting() { return isStarting && isRunning(); } /** * Opens the initial workbench window. */ /* package */void openFirstTimeWindow() { final boolean showProgress = PrefUtil.getAPIPreferenceStore().getBoolean( IWorkbenchPreferenceConstants.SHOW_PROGRESS_ON_STARTUP); if (!showProgress) { doOpenFirstTimeWindow(); } else { // We don't know how many plug-ins will be loaded, // assume we are loading a tenth of the installed plug-ins. // (The Eclipse SDK loads 7 of 86 plug-ins at startup as of // 2005-5-20) final int expectedProgressCount = Math.max(1, WorkbenchPlugin.getDefault() .getBundleCount() / 10); runStartupWithProgress(expectedProgressCount, () -> doOpenFirstTimeWindow()); } } private void doOpenFirstTimeWindow() { try { final IAdaptable input[] = new IAdaptable[1]; StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() throws Throwable { input[0] = getDefaultPageInput(); } }); openWorkbenchWindow(getDefaultPerspectiveId(), input[0]); } catch (final WorkbenchException e) { // Don't use the window's shell as the dialog parent, // as the window is not open yet (bug 76724). StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() throws Throwable { ErrorDialog.openError(null, WorkbenchMessages.Problems_Opening_Page, e .getMessage(), e.getStatus()); } }); } } private void runStartupWithProgress(final int expectedProgressCount, final Runnable runnable) { progressCount = 0; final double cutoff = 0.95; AbstractSplashHandler handler = getSplash(); IProgressMonitor progressMonitor = null; if (handler != null) progressMonitor = handler.getBundleProgressMonitor(); if (progressMonitor == null) { // cannot report progress (e.g. if the splash screen is not showing) // fall back to starting without showing progress. runnable.run(); } else { progressMonitor.beginTask("", expectedProgressCount); //$NON-NLS-1$ SynchronousBundleListener bundleListener = new StartupProgressBundleListener( progressMonitor, (int) (expectedProgressCount * cutoff)); WorkbenchPlugin.getDefault().addBundleListener(bundleListener); try { runnable.run(); progressMonitor.subTask(WorkbenchMessages.Startup_Done); int remainingWork = expectedProgressCount - Math.min(progressCount, (int) (expectedProgressCount * cutoff)); progressMonitor.worked(remainingWork); progressMonitor.done(); } finally { WorkbenchPlugin.getDefault().removeBundleListener(bundleListener); } } } @Override public IWorkbenchWindow openWorkbenchWindow(IAdaptable input) throws WorkbenchException { return openWorkbenchWindow(getDefaultPerspectiveId(), input); } @Override public IWorkbenchWindow openWorkbenchWindow(String perspectiveId, IAdaptable input) throws WorkbenchException { IPerspectiveDescriptor descriptor = getPerspectiveRegistry().findPerspectiveWithId( perspectiveId); try { MWindow window = BasicFactoryImpl.eINSTANCE.createTrimmedWindow(); return openWorkbenchWindow(input, descriptor, window, true); } catch (InjectionException e) { throw new WorkbenchException(e.getMessage(), e); } } public WorkbenchWindow openWorkbenchWindow(IAdaptable input, IPerspectiveDescriptor descriptor, MWindow window, boolean newWindow) { return (WorkbenchWindow) createWorkbenchWindow(input, descriptor, window, newWindow); } @Override public boolean restart() { return close(PlatformUI.RETURN_RESTART, false); } @Override public boolean restart(boolean useCurrrentWorkspace) { if (useCurrrentWorkspace) { URL instanceUrl = Platform.getInstanceLocation().getURL(); if (instanceUrl != null) { try { URI uri = instanceUrl.toURI(); String command_line = buildCommandLine(uri.toString()); if (command_line != null) { System.setProperty(PROP_EXIT_CODE, IApplication.EXIT_RELAUNCH.toString()); System.setProperty(IApplicationContext.EXIT_DATA_PROPERTY, command_line); } } catch (URISyntaxException e) { // do nothing; workbench will be restarted with the same // command line as used for the previous launch } } } return close(PlatformUI.RETURN_RESTART, false); } /** * Create and return a string with command line options for eclipse.exe that * will launch a new workbench that is the same as the currently running * one, but using the argument directory as its workspace. * <p> * Note that this method has been copied from * OpenWorkspaceAction.buildCommandLine(String workspace) * </p> * * @param workspace * the directory to use as the new workspace * @return a string of command line options or <code>null</code> if * 'eclipse.vm' is not set */ private String buildCommandLine(String workspace) { String property = System.getProperty(PROP_VM); if (property == null) { if (!Platform.inDevelopmentMode()) { // Don't log this when in development mode, since 'eclipse.vm' // is never set in this case WorkbenchPlugin.log(NLS.bind(WorkbenchMessages.Workbench_missingPropertyMessage, PROP_VM)); } return null; } StringBuffer result = new StringBuffer(512); result.append(property); result.append('\n'); // append the vmargs and commands. Assume that these already end in \n String vmargs = System.getProperty(PROP_VMARGS); if (vmargs != null) { result.append(vmargs); } // append the rest of the args, replacing or adding -data as required property = System.getProperty(PROP_COMMANDS); if (property == null) { result.append(CMD_DATA); result.append('\n'); result.append(workspace); result.append('\n'); } else { // find the index of the arg to add/replace its value int cmd_data_pos = property.lastIndexOf(CMD_DATA); if (cmd_data_pos != -1) { cmd_data_pos += CMD_DATA.length() + 1; result.append(property.substring(0, cmd_data_pos)); result.append(workspace); // append from the next arg int nextArg = property.indexOf("\n-", cmd_data_pos - 1); //$NON-NLS-1$ if (nextArg != -1) { result.append(property.substring(nextArg)); } } else { result.append(CMD_DATA); result.append('\n'); result.append(workspace); result.append('\n'); result.append(property); } } // put the vmargs back at the very end (the eclipse.commands property // already contains the -vm arg) if (vmargs != null) { if (result.charAt(result.length() - 1) != '\n') { result.append('\n'); } result.append(CMD_VMARGS); result.append('\n'); result.append(vmargs); } return result.toString(); } /** * Returns the ids of all plug-ins that extend the * <code>org.eclipse.ui.startup</code> extension point. * * @return the ids of all plug-ins containing 1 or more startup extensions */ public ContributionInfo[] getEarlyActivatedPlugins() { IExtensionPoint point = registry .getExtensionPoint(PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_STARTUP); IExtension[] extensions = point.getExtensions(); ArrayList<String> pluginIds = new ArrayList<>(extensions.length); for (IExtension extension : extensions) { String id = extension.getNamespaceIdentifier(); if (!pluginIds.contains(id)) { pluginIds.add(id); } } ContributionInfo[] result = new ContributionInfo[pluginIds.size()]; for (int i = 0; i < result.length; i++) { result[i] = new ContributionInfo(pluginIds.get(i), ContributionInfoMessages.ContributionInfo_EarlyStartupPlugin, null); } return result; } /** * Returns the ids of the early activated plug-ins that have been disabled * by the user. * * @return the ids of the early activated plug-ins that have been disabled * by the user */ public String[] getDisabledEarlyActivatedPlugins() { String pref = PrefUtil.getInternalPreferenceStore().getString( IPreferenceConstants.PLUGINS_NOT_ACTIVATED_ON_STARTUP); return pref.split(";"); //$NON-NLS-1$ } /* * Starts all plugins that extend the <code> org.eclipse.ui.startup </code> * extension point, and that the user has not disabled via the preference * page. */ private void startPlugins() { // bug 55901: don't use getConfigElements directly, for pre-3.0 // compat, make sure to allow both missing class // attribute and a missing startup element IExtensionPoint point = registry.getExtensionPoint(PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_STARTUP); final IExtension[] extensions = point.getExtensions(); if (extensions.length == 0) { return; } Job job = new Job("Workbench early startup") { //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { HashSet disabledPlugins = new HashSet(Arrays .asList(getDisabledEarlyActivatedPlugins())); monitor.beginTask(WorkbenchMessages.Workbench_startingPlugins, extensions.length); for (IExtension extension : extensions) { if (monitor.isCanceled() || !isRunning()) { return Status.CANCEL_STATUS; } // if the plugin is not in the set of disabled plugins, then // execute the code to start it if (!disabledPlugins.contains(extension.getNamespaceIdentifier())) { monitor.subTask(extension.getNamespaceIdentifier()); SafeRunner.run(new EarlyStartupRunnable(extension)); } monitor.worked(1); } monitor.done(); return Status.OK_STATUS; } @Override public boolean belongsTo(Object family) { return EARLY_STARTUP_FAMILY.equals(family); } }; job.setSystem(true); job.schedule(); } /** * Disable the Workbench Auto-Save job on startup during tests. * * @param b * <code>false</code> to disable the tests. */ public void setEnableAutoSave(boolean b) { workbenchAutoSave = b; } /** * Internal method for running the workbench UI. This entails processing and * dispatching events until the workbench is closed or restarted. * * @return return code {@link PlatformUI#RETURN_OK RETURN_OK}for normal * exit; {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the * workbench was terminated with a call to * {@link IWorkbench#restart IWorkbench.restart}; * {@link PlatformUI#RETURN_UNSTARTABLE RETURN_UNSTARTABLE}if the * workbench could not be started; other values reserved for future * use * @since 3.0 */ private int runUI() { UIStats.start(UIStats.START_WORKBENCH, "Workbench"); //$NON-NLS-1$ // deadlock code boolean avoidDeadlock = true; String[] commandLineArgs = Platform.getCommandLineArgs(); for (String commandLineArg : commandLineArgs) { if (commandLineArg.equalsIgnoreCase("-allowDeadlock")) { //$NON-NLS-1$ avoidDeadlock = false; } } final UISynchronizer synchronizer; if (avoidDeadlock) { UILockListener uiLockListener = new UILockListener(display); Job.getJobManager().setLockListener(uiLockListener); synchronizer = new UISynchronizer(display, uiLockListener); display.setSynchronizer(synchronizer); // declare the main thread to be a startup thread. UISynchronizer.startupThread.set(Boolean.TRUE); } else synchronizer = null; // // prime the splash nice and early // if (createSplash) // createSplashWrapper(); // ModalContext should not spin the event loop (there is no UI yet to // block) ModalContext.setAllowReadAndDispatch(false); // if the -debug command line argument is used and the event loop is // being // run while starting the Workbench, log a warning. if (WorkbenchPlugin.getDefault().isDebugging()) { display.asyncExec(() -> { if (isStarting()) { WorkbenchPlugin.log(StatusUtil.newStatus(IStatus.WARNING, "Event loop should not be run while the Workbench is starting.", //$NON-NLS-1$ new RuntimeException())); } }); } Listener closeListener = event -> event.doit = close(); // Initialize an exception handler. Window.IExceptionHandler handler = ExceptionHandler.getInstance(); try { // react to display close event by closing workbench nicely display.addListener(SWT.Close, closeListener); // install backstop to catch exceptions thrown out of event loop Window.setExceptionHandler(handler); final boolean[] initOK = new boolean[1]; // initialize workbench and restore or open one window initOK[0] = init(); if (initOK[0] && runEventLoop) { // Same registration as in E4Workbench Hashtable<String, Object> properties = new Hashtable<>(); properties.put("id", getId()); //$NON-NLS-1$ workbenchService = WorkbenchPlugin.getDefault().getBundleContext() .registerService(IWorkbench.class.getName(), this, properties); e4WorkbenchService = WorkbenchPlugin.getDefault().getBundleContext() .registerService(org.eclipse.e4.ui.workbench.IWorkbench.class.getName(), this, properties); Runnable earlyStartup = () -> { // Let the advisor run its start-up code. advisor.postStartup(); // May trigger a close/restart. // start eager plug-ins startPlugins(); addStartupRegistryListener(); }; e4Context.set(PartRenderingEngine.EARLY_STARTUP_HOOK, earlyStartup); // start workspace auto-save final int millisecondInterval = getAutoSaveJobTime(); if (millisecondInterval > 0 && workbenchAutoSave) { autoSaveJob = new WorkbenchJob(WORKBENCH_AUTO_SAVE_JOB) { @Override public IStatus runInUIThread(IProgressMonitor monitor) { if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } final int nextDelay = getAutoSaveJobTime(); try { if (applicationModelChanged) { persist(false); applicationModelChanged = false; } monitor.done(); } finally { // repeat if (nextDelay > 0 && workbenchAutoSave) { this.schedule(nextDelay); } } return Status.OK_STATUS; } }; autoSaveJob.setSystem(true); autoSaveJob.schedule(millisecondInterval); } display.asyncExec(new Runnable() { @Override public void run() { UIStats.end(UIStats.START_WORKBENCH, this, "Workbench"); //$NON-NLS-1$ UIStats.startupComplete(); } }); getWorkbenchTestable().init(display, this); // allow ModalContext to spin the event loop ModalContext.setAllowReadAndDispatch(true); isStarting = false; if (synchronizer != null) synchronizer.started(); // the event loop // runEventLoop(handler, display); } returnCode = PlatformUI.RETURN_OK; if (!initOK[0]) { returnCode = PlatformUI.RETURN_UNSTARTABLE; } } catch (final Exception e) { if (!display.isDisposed()) { handler.handleException(e); } else { String msg = "Exception in Workbench.runUI after display was disposed"; //$NON-NLS-1$ WorkbenchPlugin.log(msg, new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, 1, msg, e)); } } // restart or exit based on returnCode return returnCode; } private int getAutoSaveJobTime() { final int minuteSaveInterval = getPreferenceStore().getInt(IPreferenceConstants.WORKBENCH_SAVE_INTERVAL); final int millisecondInterval = minuteSaveInterval * 60 * 1000; return millisecondInterval; } @Override public IWorkbenchPage showPerspective(String perspectiveId, IWorkbenchWindow window) throws WorkbenchException { return showPerspective(perspectiveId, window, advisor.getDefaultPageInput()); } private boolean activate(String perspectiveId, IWorkbenchPage page, IAdaptable input) { if (page != null) { for (IPerspectiveDescriptor openedPerspective : page.getOpenPerspectives()) { if (openedPerspective.getId().equals(perspectiveId)) { if (page.getInput() == input) { WorkbenchWindow wwindow = (WorkbenchWindow) page.getWorkbenchWindow(); MWindow model = wwindow.getModel(); application.setSelectedElement(model); page.setPerspective(openedPerspective); return true; } } } } return false; } @Override public IWorkbenchPage showPerspective(String perspectiveId, IWorkbenchWindow targetWindow, IAdaptable input) throws WorkbenchException { Assert.isNotNull(perspectiveId); IPerspectiveDescriptor targetPerspective = getPerspectiveRegistry().findPerspectiveWithId( perspectiveId); if (targetPerspective == null) { throw new WorkbenchException(NLS.bind( WorkbenchMessages.WorkbenchPage_ErrorCreatingPerspective, perspectiveId)); } if (targetWindow != null) { IWorkbenchPage page = targetWindow.getActivePage(); if (activate(perspectiveId, page, input)) { return page; } } for (IWorkbenchWindow window : getWorkbenchWindows()) { IWorkbenchPage page = window.getActivePage(); if (activate(perspectiveId, page, input)) { return page; } } if (targetWindow != null) { IWorkbenchPage page = targetWindow.getActivePage(); IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); int mode = store.getInt(IPreferenceConstants.OPEN_PERSP_MODE); if (IPreferenceConstants.OPM_NEW_WINDOW != mode) { targetWindow.getShell().open(); if (page == null) { page = targetWindow.openPage(perspectiveId, input); } else { page.setPerspective(targetPerspective); } return page; } } return openWorkbenchWindow(perspectiveId, input).getActivePage(); } /* * Shuts down the application. */ private void shutdown() { // shutdown application-specific portions first try { advisor.postShutdown(); } catch (Exception ex) { StatusManager.getManager().handle( StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH, "Exceptions during shutdown", ex)); //$NON-NLS-1$ } // notify regular workbench clients of shutdown, and clear the list when // done firePostShutdown(); workbenchListeners.clear(); cancelEarlyStartup(); if (workbenchService != null) workbenchService.unregister(); workbenchService = null; if (e4WorkbenchService != null) e4WorkbenchService.unregister(); e4WorkbenchService = null; // for dynamic UI registry.removeRegistryChangeListener(extensionEventHandler); registry.removeRegistryChangeListener(startupRegistryListener); ((GrabFocus) Tweaklets.get(GrabFocus.KEY)).dispose(); // Bring down all of the services. serviceLocator.dispose(); application.getCommands().removeAll(commandsToRemove); application.getCategories().removeAll(categoriesToRemove); getDisplay().removeFilter(SWT.MouseDown, backForwardListener); backForwardListener = null; workbenchActivitySupport.dispose(); WorkbenchHelpSystem.disposeIfNecessary(); // shutdown the rest of the workbench WorkbenchColors.shutdown(); activityHelper.shutdown(); uninitializeImages(); if (WorkbenchPlugin.getDefault() != null) { WorkbenchPlugin.getDefault().reset(); } WorkbenchThemeManager.getInstance().dispose(); PropertyPageContributorManager.getManager().dispose(); ObjectActionContributorManager.getManager().dispose(); if (tracker != null) { tracker.close(); } } /** * Cancels the early startup job, if it's still running. */ private void cancelEarlyStartup() { Job.getJobManager().cancel(EARLY_STARTUP_FAMILY); // We do not currently wait for any plug-in currently being started to // complete // (e.g. by doing a join on EARLY_STARTUP_FAMILY), since they may do a // syncExec, // which would hang. See bug 94537 for rationale. } @Override public IDecoratorManager getDecoratorManager() { return WorkbenchPlugin.getDefault().getDecoratorManager(); } /** * Returns the unique object that applications use to configure the * workbench. * <p> * IMPORTANT This method is declared package-private to prevent regular * plug-ins from downcasting IWorkbench to Workbench and getting hold of the * workbench configurer that would allow them to tamper with the workbench. * The workbench configurer is available only to the application. * </p> */ /* package */ WorkbenchConfigurer getWorkbenchConfigurer() { if (workbenchConfigurer == null) { workbenchConfigurer = new WorkbenchConfigurer(); } return workbenchConfigurer; } /** * Returns the workbench advisor that created this workbench. * <p> * IMPORTANT This method is declared package-private to prevent regular * plug-ins from downcasting IWorkbench to Workbench and getting hold of the * workbench advisor that would allow them to tamper with the workbench. The * workbench advisor is internal to the application. * </p> */ /* package */ WorkbenchAdvisor getAdvisor() { return advisor; } @Override public Display getDisplay() { return display; } /** * Returns the default perspective id, which may be <code>null</code>. * * @return the default perspective id, or <code>null</code> */ public String getDefaultPerspectiveId() { return getAdvisor().getInitialWindowPerspectiveId(); } /** * Returns the default workbench window page input. * * @return the default window page input or <code>null</code> if none */ public IAdaptable getDefaultPageInput() { return getAdvisor().getDefaultPageInput(); } /** * Returns the id of the preference page that should be presented most * prominently. * * @return the id of the preference page, or <code>null</code> if none */ public String getMainPreferencePageId() { String id = getAdvisor().getMainPreferencePageId(); return id; } @Override public IElementFactory getElementFactory(String factoryId) { Assert.isNotNull(factoryId); return WorkbenchPlugin.getDefault().getElementFactory(factoryId); } @Override public IProgressService getProgressService() { return e4Context.get(IProgressService.class); } private WorkbenchActivitySupport workbenchActivitySupport; private WorkbenchCommandSupport workbenchCommandSupport; private WorkbenchContextSupport workbenchContextSupport; /** * The single instance of the binding manager used by the workbench. This is * initialized in <code>Workbench.init(Display)</code> and then never * changed. This value will only be <code>null</code> if the initialization * call has not yet completed. * * @since 3.1 */ private BindingManager bindingManager; /** * The single instance of the command manager used by the workbench. This is * initialized in <code>Workbench.init(Display)</code> and then never * changed. This value will only be <code>null</code> if the initialization * call has not yet completed. * * @since 3.1 */ private CommandManager commandManager; /** * The single instance of the context manager used by the workbench. This is * initialized in <code>Workbench.init(Display)</code> and then never * changed. This value will only be <code>null</code> if the initialization * call has not yet completed. * * @since 3.1 */ private ContextManager contextManager; @Override public IWorkbenchActivitySupport getActivitySupport() { return e4Context.get(IWorkbenchActivitySupport.class); } @Override public IWorkbenchCommandSupport getCommandSupport() { return workbenchCommandSupport; } @Override public IWorkbenchContextSupport getContextSupport() { return workbenchContextSupport; } private final IBindingManagerListener bindingManagerListener = bindingManagerEvent -> { if (bindingManagerEvent.isActiveBindingsChanged()) { updateActiveWorkbenchWindowMenuManager(true); } }; private void updateActiveWorkbenchWindowMenuManager(boolean textOnly) { final IWorkbenchWindow workbenchWindow = getActiveWorkbenchWindow(); if (workbenchWindow instanceof WorkbenchWindow) { WorkbenchWindow activeWorkbenchWindow = (WorkbenchWindow) workbenchWindow; if (activeWorkbenchWindow.isClosing()) { return; } // Update the action sets. final MenuManager menuManager = activeWorkbenchWindow.getMenuManager(); if (textOnly) { menuManager.update(IAction.TEXT); } else { menuManager.update(true); } } } private ActivityPersistanceHelper activityHelper; @Override public IIntroManager getIntroManager() { return getWorkbenchIntroManager(); } /** * @return the workbench intro manager * @since 3.0 */ /* package */WorkbenchIntroManager getWorkbenchIntroManager() { if (introManager == null) { introManager = new WorkbenchIntroManager(this); } return introManager; } private WorkbenchIntroManager introManager; /** * @return the intro extension for this workbench. * * @since 3.0 */ public IntroDescriptor getIntroDescriptor() { return introDescriptor; } /** * This method exists as a test hook. This method should * <strong>NEVER</strong> be called by clients. * * @param descriptor * The intro descriptor to use. * @since 3.0 */ public void setIntroDescriptor(IntroDescriptor descriptor) { if (getIntroManager().getIntro() != null) { getIntroManager().closeIntro(getIntroManager().getIntro()); } introDescriptor = descriptor; } /** * The descriptor for the intro extension that is valid for this workspace, * <code>null</code> if none. */ private IntroDescriptor introDescriptor; private IExtensionTracker tracker; private IRegistryChangeListener startupRegistryListener = event -> { final IExtensionDelta[] deltas = event.getExtensionDeltas(PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_STARTUP); if (deltas.length == 0) { return; } final String disabledPlugins = PrefUtil.getInternalPreferenceStore().getString( IPreferenceConstants.PLUGINS_NOT_ACTIVATED_ON_STARTUP); for (IExtensionDelta delta : deltas) { IExtension extension = delta.getExtension(); if (delta.getKind() == IExtensionDelta.REMOVED) { continue; } // if the plugin is not in the set of disabled plugins, // then // execute the code to start it if (disabledPlugins.indexOf(extension.getNamespaceIdentifier()) == -1) { SafeRunner.run(new EarlyStartupRunnable(extension)); } } }; @Override public IThemeManager getThemeManager() { return WorkbenchThemeManager.getInstance(); } /** * Returns <code>true</code> if the workbench is running, <code>false</code> * if it has been terminated. * * @return <code>true</code> if the workbench is running, <code>false</code> * if it has been terminated. */ public boolean isRunning() { return runEventLoop; } /** * <p> * Indicates the start of a large update within the workbench. This is used * to disable CPU-intensive, change-sensitive services that were temporarily * disabled in the midst of large changes. This method should always be * called in tandem with <code>largeUpdateEnd</code>, and the event loop * should not be allowed to spin before that method is called. * </p> * <p> * Important: always use with <code>largeUpdateEnd</code>! * </p> */ public final void largeUpdateStart() { if (largeUpdates++ == 0) { final IWorkbenchWindow[] windows = getWorkbenchWindows(); for (IWorkbenchWindow window : windows) { if (window instanceof WorkbenchWindow) { ((WorkbenchWindow) window).largeUpdateStart(); } } } } /** * <p> * Indicates the end of a large update within the workbench. This is used to * re-enable services that were temporarily disabled in the midst of large * changes. This method should always be called in tandem with * <code>largeUpdateStart</code>, and the event loop should not be allowed * to spin before this method is called. * </p> * <p> * Important: always protect this call by using <code>finally</code>! * </p> */ public final void largeUpdateEnd() { if (--largeUpdates == 0) { // Perform window-specific blocking. final IWorkbenchWindow[] windows = getWorkbenchWindows(); for (IWorkbenchWindow window : windows) { if (window instanceof WorkbenchWindow) { ((WorkbenchWindow) window).largeUpdateEnd(); } } } } @Override public IExtensionTracker getExtensionTracker() { return e4Context.get(IExtensionTracker.class); } /** * Adds the listener that handles startup plugins * * @since 3.1 */ private void addStartupRegistryListener() { registry.addRegistryChangeListener(startupRegistryListener); } @Override public IWorkbenchHelpSystem getHelpSystem() { return WorkbenchHelpSystem.getInstance(); } @Override public IWorkbenchBrowserSupport getBrowserSupport() { return WorkbenchBrowserSupport.getInstance(); } @Override public IViewRegistry getViewRegistry() { return WorkbenchPlugin.getDefault().getViewRegistry(); } @Override public IWizardRegistry getNewWizardRegistry() { return WorkbenchPlugin.getDefault().getNewWizardRegistry(); } @Override public IWizardRegistry getImportWizardRegistry() { return WorkbenchPlugin.getDefault().getImportWizardRegistry(); } @Override public IWizardRegistry getExportWizardRegistry() { return WorkbenchPlugin.getDefault().getExportWizardRegistry(); } @Override public final <T> T getAdapter(final Class<T> key) { return key.cast(serviceLocator.getService(key)); } @Override public final <T> T getService(final Class<T> key) { return serviceLocator.getService(key); } @Override public final boolean hasService(final Class<?> key) { return serviceLocator.hasService(key); } /** * Registers a service with this locator. If there is an existing service * matching the same <code>api</code> and it implements {@link IDisposable}, * it will be disposed. * * @param api * This is the interface that the service implements. Must not be * <code>null</code>. * @param service * The service to register. This must be some implementation of * <code>api</code>. This value must not be <code>null</code>. */ public final void registerService(final Class api, final Object service) { serviceLocator.registerService(api, service); } /** * The source provider that tracks which context menus (i.e., menus with * target identifiers) are now showing. This value is <code>null</code> * until {@link #initializeDefaultServices()} is called. */ private MenuSourceProvider menuSourceProvider; /** * Adds the ids of a menu that is now showing to the menu source provider. * This is used for legacy action-based handlers which need to become active * only for the duration of a menu being visible. * * @param menuIds * The identifiers of the menu that is now showing; must not be * <code>null</code>. * @param localSelection * @param localEditorInput */ public final void addShowingMenus(final Set menuIds, final ISelection localSelection, final ISelection localEditorInput) { menuSourceProvider.addShowingMenus(menuIds, localSelection, localEditorInput); Map currentState = menuSourceProvider.getCurrentState(); for (String key : menuSourceProvider.getProvidedSourceNames()) { e4Context.set(key, currentState.get(key)); } } /** * Removes the ids of a menu that is now hidden from the menu source * provider. This is used for legacy action-based handlers which need to * become active only for the duration of a menu being visible. * * @param menuIds * The identifiers of the menu that is now hidden; must not be * <code>null</code>. * @param localSelection * @param localEditorInput */ public final void removeShowingMenus(final Set menuIds, final ISelection localSelection, final ISelection localEditorInput) { menuSourceProvider.removeShowingMenus(menuIds, localSelection, localEditorInput); for (String key : menuSourceProvider.getProvidedSourceNames()) { e4Context.remove(key); } } @Override public boolean saveAll(final IShellProvider shellProvider, final IRunnableContext runnableContext, final ISaveableFilter filter, boolean confirm) { SaveablesList saveablesList = (SaveablesList) getService(ISaveablesLifecycleListener.class); Saveable[] saveables = saveablesList.getOpenModels(); List<Saveable> toSave = getFilteredSaveables(filter, saveables); if (toSave.isEmpty()) { return true; } if (!confirm) { return !saveablesList.saveModels(toSave, shellProvider, runnableContext); } // We must negate the result since false is cancel saveAll return !saveablesList.promptForSaving(toSave, shellProvider, runnableContext, true, false); } /* * Apply the given filter to the list of saveables */ private List<Saveable> getFilteredSaveables(ISaveableFilter filter, Saveable[] saveables) { List<Saveable> toSave = new ArrayList<>(); if (filter == null) { for (Saveable saveable : saveables) { if (saveable.isDirty()) { toSave.add(saveable); } } } else { SaveablesList saveablesList = (SaveablesList) getService(ISaveablesLifecycleListener.class); for (Saveable saveable : saveables) { if (saveable.isDirty()) { IWorkbenchPart[] parts = saveablesList.getPartsForSaveable(saveable); if (matchesFilter(filter, saveable, parts)) { toSave.add(saveable); } } } } return toSave; } /* * Test whether the given filter matches the saveable */ private boolean matchesFilter(ISaveableFilter filter, Saveable saveable, IWorkbenchPart[] parts) { return filter == null || filter.select(saveable, parts); } @Override public IShellProvider getModalDialogShellProvider() { return () -> ProgressManagerUtil.getDefaultParent(); } public IEclipseContext getContext() { return e4Context; } @Override public MApplication getApplication() { return application; } /* * Record the workbench UI in a document */ private void persistWorkbenchState() { try { XMLMemento memento = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_WORKBENCH); IStatus status = saveWorkbenchState(memento); if (status.getSeverity() == IStatus.OK) { StringWriter writer = new StringWriter(); memento.save(writer); application.getPersistedState().put(MEMENTO_KEY, writer.toString()); } else { WorkbenchPlugin.log(new Status(status.getSeverity(), PlatformUI.PLUGIN_ID, WorkbenchMessages.Workbench_problemsSavingMsg)); } } catch (IOException e) { WorkbenchPlugin.log(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, WorkbenchMessages.Workbench_problemsSavingMsg, e)); } } /* * Saves the current state of the workbench so it can be restored later on */ private IStatus saveWorkbenchState(IMemento memento) { MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, WorkbenchMessages.Workbench_problemsSaving, null); // TODO: Currently we store the editors history only. Add more if needed result.add(getEditorHistory().saveState( memento.createChild(IWorkbenchConstants.TAG_MRU_LIST))); return result; } private void restoreWorkbenchState() { try { String persistedState = application.getPersistedState().get(MEMENTO_KEY); if (persistedState != null) { XMLMemento memento = XMLMemento.createReadRoot(new StringReader(persistedState)); IStatus status = readWorkbenchState(memento); if (status.getSeverity() != IStatus.OK) { WorkbenchPlugin.log(new Status(status.getSeverity(), PlatformUI.PLUGIN_ID, WorkbenchMessages.Workbench_problemsRestoring)); } } } catch (Exception e) { WorkbenchPlugin.log(new Status( IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, WorkbenchMessages.Workbench_problemsRestoring, e)); } } private IStatus readWorkbenchState(IMemento memento) { MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, WorkbenchMessages.Workbench_problemsRestoring, null); try { UIStats.start(UIStats.RESTORE_WORKBENCH, "MRUList"); //$NON-NLS-1$ IMemento mruMemento = memento.getChild(IWorkbenchConstants.TAG_MRU_LIST); if (mruMemento != null) { result.add(getEditorHistory().restoreState(mruMemento)); } } finally { UIStats.end(UIStats.RESTORE_WORKBENCH, this, "MRUList"); //$NON-NLS-1$ } return result; } @Override public final String getId() { return id; } protected String createId() { return UUID.randomUUID().toString(); } }